﻿using System;
using System.Collections.Generic;
using System.Linq;
using FFMpegCore;
using System.Windows.Forms;
using MediaInfoLib;
using System.IO;

namespace convertToAV1OrVp9
{
    static class main
    {
        public static convertToAV1Form ctaf = new convertToAV1Form();
        public static targitVideoAudioSetting currentTargitVASetting = new targitVideoAudioSetting();
        public static List<mediaFile> medias =new List<mediaFile>();
        public static List<string> fileFullPaths = new List<string>();
        public static string ffmpegFileFullPath = string.Empty;
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);//这个是什么用的
            toAV1OrVP9.readCurrentSettingToDialog();
            toAV1OrVP9.setFFmpegFile();
            ctaf.dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;
            Application.Run(ctaf);
            
        }
    }

    class videoCoder
    {
        public static string av1 = "libsvtav1";
        public static string vp9 = "libvpx-vp9";
    }

    public enum gridFieldName { fileFullName,qp,crf, videoCoder , libvorbis , audioByteRate, videoByteRate,status }

    class treeFile
    {
        public string nameWithoutExtension;
        public string nameWithExtension;
        public string fileFullName;
        public string extension;
        public string directoryPath;
        public treeFile(string fileFullName)
        {
            this.fileFullName = fileFullName;
            this.nameWithExtension = System.IO.Path.GetFileName(fileFullName);
            this.nameWithoutExtension = System.IO.Path.GetFileNameWithoutExtension(fileFullName);
            this.extension = System.IO.Path.GetExtension(fileFullName);
            this.directoryPath = System.IO.Path.GetDirectoryName(fileFullName);
        }
    }
    class targitVideoAudioSetting
    {
        public bool ifVideo = true;
        public string useVideoCoder=videoCoder.av1;
        public int qp=40;
        public int crf = 25;
        public int videoByteRate = 2700;
        public int AudioByteRate = 128;
    }

    class mediaFile
    {
        public targitVideoAudioSetting convertSetting=new targitVideoAudioSetting();
        public IMediaAnalysis ima =null;
        public string fileFullName="";
        public int dataGridRowIndex=0;
        public string convertState="等待";
        public mediaFile(targitVideoAudioSetting tvas,IMediaAnalysis ima,string fileFullName)
        {
            this.convertSetting = tvas;
            this.ima = ima;
            this.fileFullName = fileFullName;
        }
    }


    class toAV1OrVP9//本来很多方法可以放main里，但是担心会有问题
    {
        public static void setFFmpegFile()
        {
            main.ctaf.label17.Text = Environment.GetEnvironmentVariable("FFmpegFullPath", EnvironmentVariableTarget.User);
            if (string.IsNullOrEmpty(main.ctaf.label17.Text))
            {
                inputFFmpeg iff = new inputFFmpeg();
                DialogResult dr = iff.ShowDialog();
                if (dr != DialogResult.OK)
                {
                    MessageBox.Show("没有找到FFmpeg.exe文件，程序无法运算", "需要ffmpeg.exe文件", MessageBoxButtons.OK);
                }
                main.ctaf.label17.Text = iff.ffmpegFullPath;
            }
            main.ffmpegFileFullPath = main.ctaf.label17.Text;
        }
        public static void restoreDefaultSetting()
        {
            main.currentTargitVASetting = new targitVideoAudioSetting();
            main.ctaf.qpSetting.Text = main.currentTargitVASetting.qp.ToString();
            main.ctaf.crfSetting.Text = main.currentTargitVASetting.crf.ToString();
            main.ctaf.audioByteRateSetting.Text = main.currentTargitVASetting.AudioByteRate.ToString();
            main.ctaf.videoByteRateSetting.Text = main.currentTargitVASetting.videoByteRate.ToString();
        }

        /// <summary>
        /// 批量设置，到表格
        /// </summary>
        public static void patchSettingToGrid()
        {
            for(int i=0;i<main.ctaf.dataGridView1.RowCount;i++)
            {
                main.ctaf.dataGridView1.Rows[i].Cells["qp"].Value = main.ctaf.qpSetting.Text;
                main.ctaf.dataGridView1.Rows[i].Cells[gridFieldName.crf.ToString()].Value = main.ctaf.crfSetting.Text;
                main.ctaf.dataGridView1.Rows[i].Cells[gridFieldName.audioByteRate.ToString()].Value = main.ctaf.audioByteRateSetting.Text;
                main.ctaf.dataGridView1.Rows[i].Cells[gridFieldName.videoByteRate.ToString()].Value = main.ctaf.videoByteRateSetting.Text;
                if (main.ctaf.checkBox1.Checked) main.ctaf.dataGridView1.Rows[i].Cells[gridFieldName.videoCoder.ToString()].Value = videoCoder.vp9;
                else main.ctaf.dataGridView1.Rows[i].Cells[gridFieldName.videoCoder.ToString()].Value = videoCoder.av1;
                main.ctaf.dataGridView1.Rows[i].Cells[gridFieldName.status.ToString()].Value = "等待";
            }
        }

        public static void startConvertList()
        {
            //先判断数据是否足够
            if (string.IsNullOrEmpty(main.ffmpegFileFullPath))
            {
                MessageBox.Show("没有找到FFmpeg.exe文件，程序无法运算", "需要ffmpeg.exe文件", MessageBoxButtons.OK);
                return;
            }
            if (main.medias == null || main.medias.Count() == 0)
            {
                MessageBox.Show("没有选择视频文件", "缺少视频文件", MessageBoxButtons.OK);
                return;
            }
            //
            for (int i = 0; i < main.ctaf.dataGridView1.RowCount; i++)//表格的最后一行应该是字段名的行
            {
                convertOneVideo(main.ctaf.dataGridView1.Rows[i].Cells);
            }
        }

        public static void convertOneVideo(DataGridViewCellCollection cc)
        {
            //准备转换视频
            List<string> args = new List<string>();
            args.Add("-i");
            args.Add(cc[gridFieldName.fileFullName.ToString()].Value.ToString());
            //args.Add("temp.mp4");
            args.Add("-map");
            args.Add("0:v");
            if (main.ctaf.checkBox1.CheckState == CheckState.Unchecked)
            {
                args.Add("-qp");
                args.Add(cc["qp"].Value.ToString());
            }
            else
            {
                args.Add("-b:v");
                args.Add(cc[gridFieldName.videoByteRate.ToString()].Value.ToString() + "k");
                args.Add("-crf");
                args.Add(cc["crf"].Value.ToString());
            }
            args.Add("-c:v");
            args.Add(cc[gridFieldName.videoCoder.ToString()].Value.ToString());
            args.Add("-map");
            args.Add("0:a");
            args.Add("-c:a");
            args.Add(gridFieldName.libvorbis.ToString());
            args.Add("-b:a");
            args.Add(cc[gridFieldName.audioByteRate.ToString()].Value.ToString() + "k");
            //
            treeFile tf = new treeFile(cc[gridFieldName.fileFullName.ToString()].Value.ToString());
            string outputFileName = null;
            if (main.ctaf.checkBox1.CheckState == CheckState.Unchecked)
            {
                outputFileName =System.IO.Path.Combine( tf.directoryPath , tf.nameWithoutExtension )+
                ".qp" + cc["qp"].Value.ToString()
                + ".av1" + ".webm";
            }
            else
            {
                outputFileName = System.IO.Path.Combine(tf.directoryPath, tf.nameWithoutExtension) +
                 ".crf" + cc["crf"].Value.ToString()
                 + ".vp9" + ".webm";
            }
            args.Add(outputFileName);
            //
            string[] argsArray = args.ToArray();
            string argsResult = string.Join(" ", argsArray);
            //设置准备启动外部exe文件
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.FileName = main.ffmpegFileFullPath;
            p.StartInfo.Arguments = argsResult;
            p.StartInfo.UseShellExecute = true;
            p.StartInfo.CreateNoWindow = false;
            //转换前先要给视频文件改名,主要是原来的文件名怕有问题，故要改成简单的

            //System.Environment.CurrentDirectory = fileDirectory;//要把当前的路径改到pdf文件的路径，才能转换pdf文件

            //Computer MyComputer = new Computer();
            //string currentFileFullPath = cc["fileFullName"].Value.ToString();
            //string fileExStr = System.IO.Path.GetExtension(currentFileFullPath);
            //string newTempFileName = System.IO.Path.Combine(fileDirectory, "temp", fileExStr);
            //System.IO.File.Copy(currentFileFullPath, newTempFileName);
            //MyComputer.FileSystem.RenameFile(currentFileFullPath, "temp.mp4");
            //开始转换
            p.Start();
            cc["status"].Value = "转换中";
            p.WaitForExit();
            //MyComputer.FileSystem.RenameFile((fileDirectory + "/" + "temp.mp4"),System.IO.Path.GetFileName(currentFileFullPath));

            //MyComputer.FileSystem.RenameFile((fileDirectory + "/" + "temp.webm"), newWebmFileName);
            cc["status"].Value = "完成";
        }
        public static void changeCurrentSettingAndGridList()
        {
            /*
            int.TryParse(main.ctaf.qpSetting.Text, out main.currentTargitVASetting.qp);
            int.TryParse(main.ctaf.crfSetting.Text, out main.currentTargitVASetting.crf);
            int.TryParse(main.ctaf.audioByteRateSetting.Text, out main.currentTargitVASetting.AudioByteRate);
            int.TryParse(main.ctaf.videoByteRateSetting.Text, out main.currentTargitVASetting.videoByteRate);
            */

        }

        public static void readCurrentSettingToDialog()
        {
            main.ctaf.audioByteRateSetting.Text= main.currentTargitVASetting.AudioByteRate.ToString();
            main.ctaf.videoByteRateSetting.Text = main.currentTargitVASetting.videoByteRate.ToString();
            main.ctaf.qpSetting.Text = main.currentTargitVASetting.qp.ToString();
            main.ctaf.crfSetting.Text = main.currentTargitVASetting.crf.ToString();
            if (main.currentTargitVASetting.useVideoCoder == videoCoder.av1) main.ctaf.checkBox1.Checked = false;
            else main.ctaf.checkBox1.Checked = true;
        }

        public static void patchSelectFilesAndToGrid()//也可添加
        {
            OpenFileDialog dialog = new OpenFileDialog();
            //dialog.Filter = "视频文件|*.mp4;*.mkv";
            dialog.Multiselect = true;//允许多选
            DialogResult dr = dialog.ShowDialog();
            if (dr != DialogResult.OK)
            {
                return;
            }
            List<string> newFileFullNames = dialog.FileNames.ToList();
            main.fileFullPaths = main.fileFullPaths.Union(newFileFullNames).ToList<string>();
            main.ctaf.label1.Text = "已选择：" + main.fileFullPaths.Count() + "个文件";
            if (main.fileFullPaths.Count() == 0) return;
            /*
            foreach (string fileFullPath in convertToAV1.fileFullPaths)
            {
                string fileFullPath2 = TreeAllLibrary.TreeAllLibrary.GetSafeFilename(fileFullPath);//todo:这个要记录起来，这个以后其他程序要用
            }*/
            readMediaFilesToDialog(newFileFullNames);
        }

        public static void readMediaFilesToDialog(List<string> fileFullPaths)
        {
            foreach(string fileFullPath in fileFullPaths)
            {
                var ima = FFProbe.Analyse(fileFullPath);
                mediaFile mf = new mediaFile(main.currentTargitVASetting, ima, fileFullPath);
                main.medias.Add(mf);
                saveMedaiFileToDataGrid(mf,true);
            }
            

            //var inputStream = File.OpenRead("1.mp4");
            // setting global options
            //GlobalFFOptions.Configure(new FFOptions { BinaryFolder = @".FFMPEG/bin", TemporaryFilesFolder = @"./temp" });
            /*
             * 一种获取视频音频文件数据的方法。可行的方法
            MediaInfo MI = new MediaInfo();//mediaInfo.dll无法直接引用，只能通过mediainfo.cs文件里的DllImport方法来，并且mediainfo.dll文件还要拷贝到debug目录下
            MI.Open(fileFullPath);
            string info = MI.Inform();
            string sourceVideoByteRate = MI.Get(StreamKind.Video, 0, "BitRate");
            string videoId = MI.Get(StreamKind.Video, 0, "ID");
            if (string.IsNullOrEmpty(videoId))//判断是否是视频文件
            {
            }
            */

            //一种获取视频音频文件数据的方法
            //MediaInfoLib.mi.MediaFile aviFile = new MediaFile(fileFullPath);//这句到mi就不行了
            //this.targitVP9VideoByteRate =(int) 0.0013 * this.width * this.height;//1920X1080对应的h265和vp9码率为2700
        }

        /// <summary>
        /// rowIndex为-1时，为新建表格行，否则为修改
        /// </summary>
        /// <param name="mf"></param>
        /// <param name="rowIndex"></param>
        public static void saveMedaiFileToDataGrid(mediaFile mf,bool addOrEditor)
        {
            if (addOrEditor)
            {
                mf.dataGridRowIndex = main.ctaf.dataGridView1.Rows.Add();
            }
            //todo:字段名全部要改为enum
            
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].Cells["fileFullName"].Value = mf.fileFullName;
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].Cells["fileName"].Value = System.IO.Path.GetFileName(mf.fileFullName);
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].Cells["qp"].Value = mf.convertSetting.qp;
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].Cells["status"].Value = mf.convertState;
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].Cells["crf"].Value = mf.convertSetting.crf;
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].Cells["sourceAudioByteRate"].Value = (mf.ima.PrimaryAudioStream.BitRate/1000).ToString();
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].Cells["audioByteRate"].Value = mf.convertSetting.AudioByteRate.ToString();
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].Cells["videoByteRate"].Value = mf.convertSetting.videoByteRate.ToString();
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].Cells["sourceVideoByteRate"].Value = (mf.ima.PrimaryVideoStream.BitRate/1000).ToString();
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].Cells["widthHeight"].Value = mf.ima.PrimaryVideoStream.Width.ToString() + "*" + 
                mf.ima.PrimaryVideoStream.Height.ToString();
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].Cells[gridFieldName.videoCoder.ToString()].Value = mf.convertSetting.useVideoCoder;
            
            main.ctaf.dataGridView1.Rows[mf.dataGridRowIndex].HeaderCell.Value = (mf.dataGridRowIndex+1).ToString();
        }
    }
}
